﻿using System.Diagnostics;
using System.Threading;

namespace LxBasic
{
    public class ThreadsMath
    {
        private static readonly object _Lock = new();
        private static Float128 _Sum1;
        private static Float128 _Sum2;
        private static Float128 _Sum3;
        public static void MemoryAdd(Float128 toSum1, Float128 toSum2, Float128 toSum3)
        {
            lock (_Lock)
            {
                _Sum1 += toSum1;
                _Sum2 += toSum2;
                _Sum3 += toSum3;
            }
        }
        public static void MemoryAdd(Float128 toSum1)
        {
            lock (_Lock)
            {
                _Sum1 += toSum1;
            }
        }
        public static void MemoryAdd(Float128 toSum1, Float128 toSum2)
        {
            lock (_Lock)
            {
                _Sum1 += toSum1;
                _Sum2 += toSum2;
            }
        }
        public static (double sum1, double sum2, double sum3) MemoryRecallClear()
        {
            lock (_Lock)
            {
                (double, double, double) r = ((double)_Sum1, (double)_Sum2, (double)_Sum3);
                _Sum1 = new(0);
                _Sum2 = new(0);
                _Sum3 = new(0);
                return r;
            }
        }
        public static void AddTo(ref int target, int addend)
        {
            int initialValue, computedValue;
            do
            {
                initialValue = target;
                computedValue = initialValue + addend;
            }
            while (initialValue != Interlocked.CompareExchange(ref target, computedValue, initialValue));
        }
        public static void AddTo(ref double target, double addend)//由于多线程访问顺序不确定，可能会导致舍入误差，最终蝴蝶效应引起计算结果每次都相同，因此慎用该方法
        {
            double initialValue, computedValue;
            do
            {
                initialValue = target;
                if (double.IsNaN(initialValue)) return;//NaN ！= NaN,所以排除
                computedValue = initialValue + addend;
            }
            while (initialValue != Interlocked.CompareExchange(ref target, computedValue, initialValue));
        }
        public static void KeepMax(ref double target, double potentialMax)
        {
            double initialValue;
            do
            {
                initialValue = target;
                if (double.IsNaN(initialValue)) return;//NaN ！= NaN,所以排除
                if (potentialMax <= initialValue) return;
            }
            while (initialValue != Interlocked.CompareExchange(ref target, potentialMax, initialValue));
        }
        public static void KeepMin(ref double target, double potentialMin)
        {
            double initialValue;
            do
            {
                initialValue = target;
                if (double.IsNaN(initialValue)) return;//NaN ！= NaN,所以排除
                if (potentialMin >= initialValue) return;
            }
            while (initialValue != Interlocked.CompareExchange(ref target, potentialMin, initialValue));
        }
    }
}
